package cn.xeblog.server.action.handler;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.xeblog.commons.entity.User;
import cn.xeblog.commons.entity.UserMsgDTO;
import cn.xeblog.commons.enums.Action;
import cn.xeblog.commons.enums.MessageType;
import cn.xeblog.commons.enums.Permissions;
import cn.xeblog.server.action.ChannelAction;
import cn.xeblog.server.action.pina.LimitUtil;
import cn.xeblog.server.action.specialAc.SpecialCommandHandler;
import cn.xeblog.server.action.timer.TokenBucket;
import cn.xeblog.server.action.timer.TokenBucketFactory;
import cn.xeblog.server.annotation.DoAction;
import cn.xeblog.server.builder.ResponseBuilder;
import cn.xeblog.server.cache.UserCache;
import cn.xeblog.server.config.GlobalConfig;
import cn.xeblog.server.util.SensitiveWordUtils;

/**
 * @author anlingyi
 * @date 2020/8/14
 */
@DoAction(Action.CHAT)
public class ChatActionHandler extends AbstractActionHandler<UserMsgDTO> {

    private static final TimedCache<String, Integer> warningCache = CacheUtil.newTimedCache(10 * 60 * 1000);
    private static final TimedCache<String, Integer> ipCache = CacheUtil.newTimedCache(20 * 60 * 1000);

    @Override
    protected void process(User user, UserMsgDTO body) {
        if (!user.hasPermit(Permissions.SPEAK)) {
            user.send(ResponseBuilder.system("您已被禁言！"));
            return;
        }
        if (!Permissions.SPEAK.hasPermit(GlobalConfig.GLOBAL_PERMIT)) {
            user.send(ResponseBuilder.system("鱼塘已开启全员禁言！"));
            return;
        }

        if (body.getToUsers() != null && body.getToUsers().length > 2) {
            user.send(ResponseBuilder.system("仅允许艾特1人！"));
            return;
        }

        boolean checkLimit = LimitUtil.checkLimit(user);
        if (checkLimit) {
            user.send(ResponseBuilder.system("发言限制！"));
            return;
        }
        // 用户消息高频限制
        String userId = user.getId();
        if (TokenBucketFactory.getTokenBucket(userId) == null) {
            TokenBucketFactory.registerTokenBucket(new TokenBucket(userId));
        }
        if (warningCache.get(userId) == null) {
            warningCache.put(userId, 0);
        }

        String userIp = user.getIp();
        if (ipCache.get(userIp) == null) {
            ipCache.put(userIp, 0);
        }

        // ip被踢下线两次就拉黑
        Integer ipCount = ipCache.get(userIp);
        if (ipCount >= 2) {
            SpecialCommandHandler.blackControlAdd(user);
            user.send(ResponseBuilder.system("你已经被拉黑，若要解除，请联系管理员！"));
            ipCache.remove(userIp);
            ipCount = 0;
        }

        // 警告超过三次踢下线
        Integer warningCount = warningCache.get(userId);
        if (warningCount >= 3) {
            user.send(ResponseBuilder.system("消息发送过于频繁，下线冷静冷静！"));
            ThreadUtil.sleep(100);
            ipCache.put(userIp, ipCount + 1);
            ChannelAction.forceOffline(user);
            return;
        }

        boolean success = TokenBucketFactory.getTokenBucket(userId).getAndConsumeToken();
        if (!success) {
            user.send(ResponseBuilder.system("高频次消息警告！超过三次踢下线！"));
            warningCache.put(userId, warningCount + 1);
            return;
        }

        if (body.getMsgType() == UserMsgDTO.MsgType.TEXT) {
            String msg = Convert.toStr(body.getContent());

            if (!user.isAdmin() && StrUtil.length(msg) > 200) {
                user.send(ResponseBuilder.system("发送的内容长度不能超过200字符！"));
                return;
            }

            if (!user.isAdmin() && SensitiveWordUtils.hasSensitiveWord(msg)) {
                body.setContent(SensitiveWordUtils.loveChina(msg));
                ChannelAction.send(user, body, MessageType.USER);
                return;
            }

            if (!SpecialCommandHandler.customSendMessage(user, body, msg)) {
                return;
            }
        } else {
            // 暂时不支持这种形式的消息，全部转为文本消息
            body.setMsgType(UserMsgDTO.MsgType.TEXT);
        }

        ChannelAction.send(user, body, MessageType.USER);
        // 正常发言标记为活跃用户
        UserCache.addActiveUser(user);
    }

}
